#include <stdio.h> // perror()
#include <stdlib.h> // exit()
#include <unistd.h> // ftruncate() / close() / fork() / sleep()
#include <fcntl.h> // pid_t / 
#include <sys/mman.h> // shm_open()/shm_unlink()/mmap()/munmap()
#include <wait.h> // wait()
#include <string.h> // strcpy()

int main()
{
    char *shm_name = "/shm_test"; // 共享对象文件的默认位置在：/dev/shm/

    // 创建共享对象，返回共享对象对应虚拟文件的描述符
    int fd = shm_open(shm_name, O_CREAT | O_RDWR, 0644);
    if (fd < 0)
    {
        perror("创建共享内存对象失败!\n");
        exit(EXIT_FAILURE);
    }
    
    // 将共享对象扩充为100字节长度
    ftruncate(fd, 100);

    // 开辟对应的共享虚拟内存
    // 将共享对象以读写方式映射到虚拟共享内存(当前不开辟物理内存)，并开启父子共享标签 偏移量选择0从头开始
    // 返回内存地址
    char *share = (char *) mmap(NULL, 100, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);

    // 如果映射失败， 提示并退出
    if (share == MAP_FAILED)
    {
        perror("共享内存对象映射到内存失败!\n");
        exit(EXIT_FAILURE);
    }
    // 映射区建立完毕,关闭读取连接 注意不是删除
    close(fd);

    // 创建子进程
    pid_t pid = fork();
    if (pid == 0) // 子进程
    {
        // 子进程中：向共享内存中写入数据（此时产生将数据保存到物理内存）
        char *msg = "你是个好人!";
        strcpy(share, msg);
        
        printf("子进程向共享内存中写入数据：%s \n", msg);

        // sleep(2);
        // printf("子进程读取父进程写入的数据：%s \n", share);
    }
    else
    {
        // 父进程休眠1秒，让子进程先执行写入数据
        sleep(1);

        // 父进程读取共享内存中的数据，并输出
        printf("父进程读取子进程写入的数据：%s \n", share);

        // printf("父进程向共享内存中写入的数据：%s \n", "abcd");
        // strcpy(share, "abcd");

        // 等待所有子进程运行结束
        wait(NULL);

        // 释放共享内存
        munmap(share, 100);

        // 删除共享内存对象  /dev/shm/shm_test
        shm_unlink(shm_name);
    }
    
    return 0;
}